/**
 * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jse.tpl;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.jse.Lang;

/**
 * EngineConfig
 */
public class EngineConfig {

//	WriterBuffer writerBuffer = new WriterBuffer();

//	public Compressor compressor = new Compressor();

	private List<Source> sharedFunctionSourceList = new ArrayList<Source>();		// for devMode only

	Map<String, Object> sharedObjectMap = null;

//	private OutputDirectiveFactory outputDirectiveFactory = OutputDirectiveFactory.me;
//	private Map<String, Class<? extends Directive>> directiveMap = new HashMap<String, Class<? extends Directive>>(64, 0.5F);
	private SharedMethodKit sharedMethodKit = new SharedMethodKit();

	// 保留指令所在行空白字符的指令
	private Set<String> keepLineBlankDirectives = new HashSet<>();

	private boolean devMode = false;
	private boolean reloadModifiedSharedFunctionInDevMode = true;
//	private String baseTemplatePath;//TODO 临时为classpath路径
//	private String datePattern = "yyyy-MM-dd HH:mm:ss";

	// 浮点数输出与运算时使用的舍入模式，默认值为 "四舍五入"
	
	private boolean supportStaticMethodExpression = false;
	private boolean supportStaticFieldExpression = false;

	public EngineConfig() {
		// 内置指令 #() 与 #include() 需要配置，保留指令所在行前后空白字符以及行尾换行字符 '\n'
		setKeepLineBlank("output", true);
		setKeepLineBlank("include", true);

		// Add official directive of Template Engine
//		addDirective("render", RenderDirective.class, true);

		// 添加共享方法到引擎
		addSharedMethod(Lang.class);
	}

	/**
	 * Add shared function with files
	 */
	public void addSharedFunction(String... fileNames) {
		for (String fileName : fileNames) {
			addSharedFunction(fileName);
		}
	}

	public synchronized void addSharedObject(String name, Object object) {
		if (sharedObjectMap == null) {
			sharedObjectMap = new HashMap<String, Object>(64, 0.25F);
		} else if (sharedObjectMap.containsKey(name)) {
			throw new IllegalArgumentException("Shared object already exists: " + name);
		}
		sharedObjectMap.put(name, object);
	}

	public Map<String, Object> getSharedObjectMap() {
		return sharedObjectMap;
	}

	public synchronized void removeSharedObject(String name) {
		if (sharedObjectMap != null) {
			sharedObjectMap.remove(name);
		}
	}

	/**
	 * Set output directive factory
	 */
//	public void setOutputDirectiveFactory(OutputDirectiveFactory outputDirectiveFactory) {
//		if (outputDirectiveFactory == null) {
//			throw new IllegalArgumentException("outputDirectiveFactory can not be null");
//		}
//		this.outputDirectiveFactory = outputDirectiveFactory;
//	}
//
//	public Output getOutputDirective(ExprList exprList, Location location) {
//		return outputDirectiveFactory.getOutputDirective(exprList, location);
//	}

	/**
	 * Invoked by Engine only
	 */
	void setDevMode(boolean devMode) {
		this.devMode = devMode;
	}

	public boolean isDevMode() {
		return devMode;
	}

//	public void setBaseTemplatePath(String baseTemplatePath) {
//		// 使用 ClassPathSourceFactory 时，允许 baseTemplatePath 为 null 值
//		if (baseTemplatePath == null) {
//			this.baseTemplatePath = null;
//			return ;
//		}
//		if (Strings.isBlank(baseTemplatePath)) {
//			throw new IllegalArgumentException("baseTemplatePath can not be blank");
//		}
//		baseTemplatePath = baseTemplatePath.trim();
//		baseTemplatePath = baseTemplatePath.replace("\\", "/");
//		if (baseTemplatePath.length() > 1) {
//			if (baseTemplatePath.endsWith("/")) {
//				baseTemplatePath = baseTemplatePath.substring(0, baseTemplatePath.length() - 1);
//			}
//		}
//		this.baseTemplatePath = baseTemplatePath;
//	}
//
//	public String getBaseTemplatePath() {
//		return baseTemplatePath;
//	}

//	public void setBufferSize(int bufferSize) {
//		writerBuffer.setBufferSize(bufferSize);
//	}
//
//	public void setReentrantBufferSize(int reentrantBufferSize) {
//		writerBuffer.setReentrantBufferSize(reentrantBufferSize);
//	}

	/**
	 * 配置自己的 WriterBuffer 实现，配置方法：
	 * engine.getEngineConfig().setWriterBuffer(...);
	 */
//	public void setWriterBuffer(WriterBuffer writerBuffer) {
//		Objects.requireNonNull(writerBuffer, "writerBuffer can not be null");
//		this.writerBuffer = writerBuffer;
//	}

	public void setReloadModifiedSharedFunctionInDevMode(boolean reloadModifiedSharedFunctionInDevMode) {
		this.reloadModifiedSharedFunctionInDevMode = reloadModifiedSharedFunctionInDevMode;
	}

	public void setKeepLineBlank(String directiveName, boolean keepLineBlank) {
		if (keepLineBlank) {
			keepLineBlankDirectives.add(directiveName);
		} else {
			keepLineBlankDirectives.remove(directiveName);
		}
	}

	public Set<String> getKeepLineBlankDirectives() {
		return keepLineBlankDirectives;
	}

	/**
	 * Add shared method from object
	 */
	public void addSharedMethod(Object sharedMethodFromObject) {
		sharedMethodKit.addSharedMethod(sharedMethodFromObject);
	}

	/**
	 * Add shared method from class
	 */
	public void addSharedMethod(Class<?> sharedMethodFromClass) {
		sharedMethodKit.addSharedMethod(sharedMethodFromClass);
	}

	/**
	 * Add shared static method of Class
	 */
	public void addSharedStaticMethod(Class<?> sharedStaticMethodFromClass) {
		sharedMethodKit.addSharedStaticMethod(sharedStaticMethodFromClass);
	}

	/**
	 * Remove shared Method with method name
	 */
	public void removeSharedMethod(String methodName) {
		sharedMethodKit.removeSharedMethod(methodName);
	}

	/**
	 * Remove shared Method of the Class
	 */
	public void removeSharedMethod(Class<?> sharedClass) {
		sharedMethodKit.removeSharedMethod(sharedClass);
	}

	/**
	 * Remove shared Method
	 */
	public void removeSharedMethod(Method method) {
		sharedMethodKit.removeSharedMethod(method);
	}

	/**
	 * Remove shared Method
	 */
	public void removeSharedMethod(String methodName, Class<?>... paraTypes) {
		sharedMethodKit.removeSharedMethod(methodName, paraTypes);
	}

	public SharedMethodKit getSharedMethodKit() {
		return sharedMethodKit;
	}

//	public void setCompressor(Compressor compressor) {
//		this.compressor = compressor;
//	}
//
//	public Compressor getCompressor() {
//		return compressor;
//	}
	
	/**
     * 设置为 true 支持静态方法调用表达式，自 jfinal 5.0.2 版本开始默认值为 false
     */
    public void setStaticMethodExpression(boolean enable) {
        this.supportStaticMethodExpression = enable;
    }
    
    public boolean isStaticMethodExpressionEnabled() {
        return supportStaticMethodExpression;
    }
    
    /**
     * 设置为 true 支持静态属性访问表达式，自 jfinal 5.0.2 版本开始默认值为 false
     */
    public void setStaticFieldExpression(boolean enable) {
        this.supportStaticFieldExpression = enable;
    }
    
    public boolean isStaticFieldExpressionEnabled() {
        return supportStaticFieldExpression;
    }
}





